package checkClass;

import java.util.ArrayList;
import java.util.Objects;

/*
    类型表达式节点，每一个类型都有一个对应的类型表达式
    类型相同与否即等价于类型表达式的相同与否
    2022-3-11-杨海南
 */
public class TypeExpression {
    //实际的类型表达式，可能是基本类型也可能是构造类型也可能是工具类型
    private TypeNode typeNode;

    public TypeExpression(TypeConstructor typeConstructor) {
        this.typeNode = typeConstructor;
    }

    public TypeExpression(BaseTypeEnum baseTypeEnum) {
        this.typeNode = baseTypeEnum;
    }

    public TypeExpression(ToolTypeEnum toolTypeEnum) {
        this.typeNode = toolTypeEnum;
    }

    public TypeExpression(TypeNode typeNode) {
        this.typeNode = typeNode;
    }

    public TypeExpression(ParaName paraName) {
        this.typeNode = paraName;
    }


    public TypeNode getTypeNode() {
        return typeNode;
    }

    //判断两个类型是否相同
    public boolean typeEquals(TypeNode typeNode) {
        if (typeNode instanceof BaseTypeEnum && this.typeNode instanceof BaseTypeEnum) {
            //同为基本数据类型
            if (typeNode == this.typeNode) {
                return true;
            }
            return false;
        } else if (typeNode instanceof TypeConstructor && this.typeNode instanceof TypeConstructor) {
            //同为构造类型
            return constructorEquals((TypeConstructor) typeNode);
        }
        return false;
    }

    public boolean typeEquals(TypeExpression typeExpression) {
        TypeNode typeNode = typeExpression.getTypeNode();
        return this.typeEquals(typeNode);
    }

    public void setTypeNode(TypeNode typeNode) {
        this.typeNode = typeNode;
    }

    //这里编写比较两个构造类型是否相等
    public boolean constructorEquals(TypeConstructor typeConstructor) {
        System.out.println("enter consEqual");
        //等价于比较两个N叉树是否相等
        if (((TypeConstructor) this.typeNode).getSonList().size() == typeConstructor.getSonList().size()) {
            return sonEquals((TypeConstructor) this.typeNode, typeConstructor);
        } else {
            return false;
        }
    }

    //这里直接递归写吧，类型表达式这个树不会太深的
    private boolean sonEquals(TypeConstructor typeConstructor1, TypeConstructor typeConstructor2) {
        System.out.println("enter sonEquals");
        ArrayList<TypeNode> sonList1 = typeConstructor1.getSonList();
        ArrayList<TypeNode> sonList2 = typeConstructor2.getSonList();
        int size = typeConstructor1.getSonList().size();
        for (int i = 0; i < size; i++) {
            TypeNode typeNode1 = sonList1.get(i);
            TypeNode typeNode2 = sonList2.get(i);
            if (typeNode1 instanceof ParaName && typeNode2 instanceof ParaName) {
                if (!((ParaName) typeNode1).paraEquals((ParaName) typeNode2)) {
                    return false;
                }
            } else if (typeNode1 instanceof BaseTypeEnum && typeNode2 instanceof BaseTypeEnum) {
                if (typeNode1 != typeNode2) {
                    return false;
                }
            } else if (typeNode1 instanceof TypeConstructor && typeNode2 instanceof TypeConstructor) {
                if (!sonEquals((TypeConstructor) typeNode1, (TypeConstructor) typeNode2)) {
                    return false;
                }
            }
        }
        return true;
    }

    public int getArrayDepth() {
        return ((TypeConstructor) typeNode).getArrayDepth();
    }
}
